package fr.mystnihon.game.model.actor;

import java.util.HashMap;
import java.util.Map;

import android.graphics.Bitmap;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceView;
import fr.mystnihon.game.model.graphic.Animation;
import fr.mystnihon.game.model.graphic.Sprite;

public class Actor extends Sprite {

	public interface OnActionListener {
		public void onTouched(boolean touched);
	}

	private static final float VELOCITY = 0.1f;

	private static final String TAG = Actor.class.getSimpleName();

	private OnActionListener mOnActionListener;

	private boolean touched;

	private Map<String, Animation> animList;

	public Actor(Bitmap bitmap, int x, int y) {
		super();
		loadDefaultAnim();
		setBitmap(bitmap);
		setX(x);
		setY(y);
		standby();
	}

	public Actor(Animation animation) {
		super(animation);
		touched = false;
	}

	private void setTouched(boolean touched) {
		this.touched = touched;
		if (mOnActionListener != null) {
			mOnActionListener.onTouched(touched);
		}
	}

	/**
	 * Handles the {@link MotionEvent.ACTION_DOWN} event. If the event happens
	 * on the bitmap surface then the touched state is set to <code>true</code>
	 * otherwise to <code>false</code>
	 * 
	 * @param eventX
	 *            - the event's X coordinate
	 * @param eventY
	 *            - the event's Y coordinate
	 */
	public void handleActionDown(int eventX, int eventY) {
		if (eventX >= (getX() - getBitmap().getWidth() / 2)
				&& (eventX <= (getX() + getBitmap().getWidth() / 2))) {
			if (eventY >= (getY() - getBitmap().getHeight() / 2)
					&& (eventY <= (getY() + getBitmap().getHeight() / 2))) {
				// droid touched
				setTouched(true);
			} else {
				setTouched(false);
			}
		} else {
			setTouched(false);
		}

	}

	public boolean handleActions(MotionEvent event, SurfaceView panel) {
		standby();
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			// delegating event handling to the droid
			handleActionDown((int) event.getX(), (int) event.getY());

			// check if in the lower part of the screen we exit
		}
		if (event.getAction() == MotionEvent.ACTION_MOVE) {
			log("Move!");
			// the gestures
			if (isTouched()) {
				return true;
			}
			// move player

			if (event.getY() > panel.getHeight() / 2) {
				if ((getPosRectangle().bottom < panel.getHeight())) {
					// move down.
					log("Down!");
					moveDown();
				}
			} else if (event.getY() < panel.getHeight() / 2) {
				if ((getPosRectangle().top > 0)) {
					// move up
					log("Up!");
					moveUp();
				}
			}
			if (event.getX() > panel.getWidth() / 2) {
				if (!(getPosRectangle().right >= panel.getWidth())) {
					// move right.
					moveRight();
				}
			} else if (event.getX() < panel.getWidth() / 2) {
				if (!(getPosRectangle().left <= 0)) {
					// move left
					moveLeft();
				}
			}

			refreshAnim();
		}
		if (event.getAction() == MotionEvent.ACTION_UP) {
			log("up");
			// touch was released
			if (isTouched()) {
				setTouched(false);
			}
			standby();
			refreshAnim();
		}
		return true;
	}

	public void loadAnimation(HashMap<String, Animation> animList) {
		this.animList = animList;
	}

	private void loadDefaultAnim() {
		animList = new HashMap<String, Animation>();

		animList.put("down", generateDefaultPattern(1));

		animList.put("left", generateDefaultPattern(2));
		animList.put("right", generateDefaultPattern(3));
		animList.put("up", generateDefaultPattern(4));
		animList.put("still_down", generateDefaultStill(1));
		animList.put("still_left", generateDefaultStill(2));
		animList.put("still_right", generateDefaultStill(3));
		animList.put("still_up", generateDefaultStill(4));

		anim = (animList.get("left"));
	}

	// Unique variable to prevent multiple memory allocation.
	Animation myanim;

	/**
	 * 
	 * @param line
	 * @return
	 */
	public Animation generateDefaultPattern(int line) {
		int y = (line - 1) * 32;
		myanim = new Animation();
		myanim.addFrame(500, 0, y, 32, 32);
		myanim.addFrame(400, 32, y, 32, 32); // REPOS
		myanim.addFrame(500, 64, y, 32, 32);
		myanim.addFrame(400, 32, y, 32, 32); // REPOS
		myanim.addFrame(500, 0, y, 32, 32);
		myanim.addFrame(400, 32, y, 32, 32); // REPOS
		myanim.addFrame(500, 64, y, 32, 32);
		myanim.addFrame(400, 32, y, 32, 32); // REPOS
		return myanim;
	}

	public Animation generateDefaultStill(int line) {
		int y = (line - 1) * 32;
		myanim = new Animation();
		myanim.addFrame(100000L, 32, y, 32, 32);
		return myanim;
	}

	public boolean isTouched() {
		return touched;
	}

	public void moveUp() {
		log("Moved up!");
		setVelocityY(-1f * VELOCITY);
	}

	public void moveRight() {
		setVelocityX(1f * VELOCITY);
	}

	public void moveDown() {
		log("Moved down!");
		setVelocityY(1f * VELOCITY);
	}

	public void moveLeft() {
		setVelocityX(-1f * VELOCITY);
	}

	String animToSet = "";
	String animSet = "";

	public void refreshAnim() {

		if (getVelocityY() > 0) {
			animToSet = "down";
		} else if (getVelocityY() < 0) {
			animToSet = "up";
		}

		if (getVelocityX() > 0) {
			animToSet = "right";
		} else if (getVelocityX() < 0) {
			animToSet = "left";
		}

		if (0 == getVelocityX() && 0 == getVelocityY()) {
			if (animSet == "down") {
				animToSet = "still_down";
			} else if (animSet == "up") {
				animToSet = "still_up";
			} else if (animSet == "left") {
				animToSet = "still_left";
			} else if (animSet == "right") {
				animToSet = "still_right";
			}
		}

		if (animToSet != animSet) {
			animSet = animToSet;
			if (animList.containsKey(animToSet)) {
				setAnimation(animList.get(animToSet));
			}
		}
	}

	public void jump() {

	}

	public void standby() {
		setVelocityX(0f);
		setVelocityY(0f);
	}

	private static final boolean FORCE_LOG = false;

	private final void log(String msg) {
		if (FORCE_LOG) {
			Log.d(TAG, msg);
		}
	}
}
